package com.hubu.map;
public class SimpleHashMap<K,V>{
    private static final int DEFAULT_CAPACITY=16;
    Entry<K,V> []table=null;
    private int size=0;
    private int capacity=0;
    private int threshold=0;
    public SimpleHashMap(){
        this.capacity=DEFAULT_CAPACITY;
        this.threshold=(int)(0.75*this.capacity);
    }
    public V put(K key,V value){
        int length=0;
        if(table==null||(length=table.length)==0) {
            table = new Entry[this.capacity];
        }
        int hash=hash(key);
        int index=indexFor(hash,table.length);
        if(size>=threshold&&table[index]!=null){
            resize(2*this.capacity);
        }

        if(table[index]==null){
            table[index]=new Entry<>(key,value,hash,null);
            size++;
            return null;
        }
        Entry<K,V> current=table[index];
        while(true){
            if(current.key==key||(current.hash==hash&&current.key.equals(key))){
                V oldValue=current.value;
                current.value=value;
                return oldValue;
            }
            if(current.next==null){
                break;
            }
            current=current.next;
        }
        table[index]=new Entry<>(key,value,hash,table[index]);
        size++;
        return null;
    }
    private void resize(int newCapacity) {
        Entry<K,V> newTable[]=new Entry[newCapacity];
        for(int i=0;i<table.length;i++){
            if(table[i]!=null){
                Entry<K,V> current=table[i];
                Entry<K,V> next=null;
                while(current!=null){
                    int index=indexFor(current.hash,newTable.length);
                    next=current.next;
                    current.next=newTable[index];
                    newTable[index]=current;
                    current=next;
                }
            }
        }
        this.threshold=(int)(this.capacity*0.75);
        this.capacity=newCapacity;
        this.table=newTable;
    }
    private int indexFor(int hash,int tableLength){
        return hash&(tableLength-1);
    }
    private int hash(K key){
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }
    public int size(){
        return size;
    }
    public V get(K key){
        int hash=hash(key);
        int index=indexFor(hash,table.length);
        Entry<K,V> current=table[index];
        while(current!=null){
            if((hash==current.hash&&key.equals(current.key))||key==current.key){
                return current.value;
            }
            current=current.next;
        }
        return null;
    }
    public V remove(K key){
        int hash=hash(key);
        int index=indexFor(hash,table.length);
        Entry<K,V> current=table[index];
        if(current==null){
            return null;
        }
        if(current.hash==hash&&current.key.equals(key)||current.key==key){
            size--;
            Entry<K,V> temp=current;
            V value=current.value;
            table[index]=table[index].next;
            temp.next=null;
            return value;
        }
        while(current.next!=null){
            if(current.next.hash==hash&&current.next.key.equals(key)||current.next.key==key){
                size--;
                Entry<K,V> temp=current.next;
                V value=current.next.value;
                current=current.next.next;
                temp.next=null;
                return value;
            }
        }
        return null;
    }
    public int capacity(){
        return capacity;
    }
    static class Entry<K,V>{
        K key;
        V value;
        int hash;
        Entry<K,V> next;
        Entry(K key,V value,int hash,Entry<K,V> next){
            this.key=key;
            this.value=value;
            this.hash=hash;
            this.next=next;
        }
    }
}
